package renpyas3.model 
{
	import br.com.stimuli.loading.BulkLoader;
	import br.com.stimuli.loading.BulkProgressEvent;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import org.osflash.thunderbolt.Logger;
	import renpyas3.model.structs.RenpyLabelBlock;
	import renpyas3.model.structs.RenpyOptions;
	import renpyas3.model.structs.RenpyScreen;
	import flash.events.Event;
	
	/**
	 * main model access point
	 * a game is made one or more screen
	 */
	public class RenpyPlayerModel
	{
		//model data
		private var _currentScreen:RenpyScreen;
		private var _currentLabelBlock:RenpyLabelBlock;
		private var _mainScreen:RenpyScreen;
		private var _assetsLoader:AssetsLoader;
		private var _assetsScreenWidth:Number;
		private var _assetsScreenHeight:Number;
		private var _options:RenpyOptions;
		private var _path:String;
		
		public function RenpyPlayerModel(path:String,options:RenpyOptions,embeds:Embeds) 
		{
			_options = options;
			_path = path;
			_assetsLoader = new AssetsLoader(embeds, "main");
			startLoadingOptions();
		}
		
		/**
		 * load options first
		 */
		private function startLoadingOptions():void
		{
			Logger.info("RenpyPlayerModel::constructor: loading "+_path + "options.rpy");
			var classDef:Object = _assetsLoader.getEmbeddedObjectDefinition(_path + "options.rpy")
			if (classDef != null)
			{
				//'load' from embed
				var optionsRpyAsString:String =  new classDef();
				readOptionsRpyData(optionsRpyAsString);
			}
			else
			{
				//load from file
				var scriptFileLoader:URLLoader = new URLLoader();
				scriptFileLoader.addEventListener(Event.COMPLETE, handleOptionsFileLoaded);
				scriptFileLoader.addEventListener(IOErrorEvent.IO_ERROR, handleLoadIOerror,false,0,true);
				scriptFileLoader.load(new URLRequest(_path + "options.rpy"));
			}
		}
		
		
		/**
		 * options for menu loaded
		 */
		private function handleOptionsFileLoaded(e:Event):void
		{
			Logger.info("RenpyPlayerModel::handleOptionsFileLoaded, options loaded: read them");
			readOptionsRpyData(e.target.data);
		}

		private function readOptionsRpyData(data:String):void 
		{
			Logger.info("RenpyPlayerModel::handleOptionsFileLoaded, options loaded, now load script:"+_path + "script.rpy");
			var arrayOfOptionLines:/*String*/Array = data.split(/\n/);
			var vectorOfOptionLines:Vector.<String> = Vector.<String>(arrayOfOptionLines);
			_options = new RenpyOptions(vectorOfOptionLines);
			_assetsScreenWidth = options.screenWidth;
			_assetsScreenHeight = options.screenHeight;
			
			startLoadingScript();
		}
		
		/**
		 * load game script after options
		 */
		private function startLoadingScript():void
		{
			
			var classDef:Object = _assetsLoader.getEmbeddedObjectDefinition(_path + "script.rpy")
			if (classDef != null)
			{
				//'load' from embed
				var scriptAsString:String =  new classDef();
				readScriptData(scriptAsString);
			}
			else
			{
				//load from file
				var scriptFileLoader:URLLoader = new URLLoader();
				scriptFileLoader.addEventListener(Event.COMPLETE, handleScriptFileLoaded);
				scriptFileLoader.addEventListener(IOErrorEvent.IO_ERROR, handleLoadIOerror,false,0,true);
				scriptFileLoader.load(new URLRequest(_path + "script.rpy"));			
				//scriptFileLoader.load(new URLRequest(_path + "script.txt"));		
			}
		}

		/**
		 * script loaded
		 */
		private function handleScriptFileLoaded(e:Event):void 
		{
			Logger.info("RenpyPlayerModel::handleScriptFileLoaded, scriptloaded; start parsing");
			readScriptData(e.target.data);
		}
		
		/**
		 * show error if optios or script files fail loading
		 */
        private function handleLoadIOerror(e:IOErrorEvent):void 
		{
			Logger.error("RenpyPlayerModel::handleLoadIOerror can't load file. " + (e.text));
        }

		
		private function readScriptData(data:String):void 
		{
			var arrayOfScriptLines:/*String*/Array = data.split(/\n/);
			var vectorOfScriptLines:Vector.<String> = Vector.<String>(arrayOfScriptLines);
			
			_mainScreen = new RenpyScreen(vectorOfScriptLines, path, _assetsLoader);
			
			Logger.info("RenpyPlayerModel::constructor, _assetsLoader.itemsTotal:"+_assetsLoader.itemsTotal) 
			if (_assetsLoader.itemsTotal > 0)
			{
				_assetsLoader.addEventListener(BulkLoader.PROGRESS, handleAsstesLoadProgress);
				_assetsLoader.start();
			}
			else
			{
				handleAssetsLoadComplete();
			}
		}
		
		private function handleAsstesLoadProgress(e:BulkProgressEvent):void 
		{
			//trace("PercentLoaded --e.percentLoaded, e.weightPercent:" + e.percentLoaded, e.weightPercent);
			//trace("PercentLoaded --e.itemsLoaded, e.itemsTotal:" + e.itemsLoaded, e.itemsTotal);
			if (e.itemsLoaded == e.itemsTotal)
			{
				handleAssetsLoadComplete();
			}
		}
		
		private function handleAssetsLoadComplete():void
		{
			Logger.info("RenpyPlayerModel::constructor, handleAssetsLoadComplete") 
			_currentScreen = _mainScreen;
			_currentLabelBlock = _currentScreen.labelBlocks[0];
			_currentLabelBlock.enterBlock();
		}
		
		/**
		 * Jump to a given label block and start 
		 */
		public function jumpToLabelBlock(labelName:String):void
		{
			if(_currentScreen.labelBlocksDictionary[labelName] != null)
			{
				_currentLabelBlock = _currentScreen.labelBlocksDictionary[labelName];
				_currentLabelBlock.enterBlock();
			}
			else
			{
				Logger.error("RenpyPlayerModel::jumpToLabelBlock ERROR --label not found:"+labelName+"<");
			}
		}
		
		/**
		 * Jump to next label block in the sequence
		 */
		public function jumpToNextLabelBlockInSequence():void
		{
			if (_currentLabelBlock.nextLabelBlockIndex != -1)
			{
				_currentLabelBlock = _currentScreen.labelBlocks[_currentLabelBlock.nextLabelBlockIndex];
				_currentLabelBlock.enterBlock();
			}
		}

		/**
		 * Jump to another line of code in the curreny labbelBlock
		 * after a menu choice
		 */
		public function moveInstructionPointerToIndex(nextInstructionIndex:uint):void
		{
			_currentLabelBlock.moveInstructionPointerToIndex(nextInstructionIndex);
		}


		/**
		 * called on 'return' instruction to return to prev screen
		 */
		public function returnToPreviousScreen():void
		{
			//make it end for now:
			_currentScreen = null;
			_currentLabelBlock = null;
			//_currentScreen = _prevScreen;
		}
		
		public function get currentScreen():RenpyScreen { return _currentScreen; }
		
		public function get currentLabelBlock():RenpyLabelBlock { return _currentLabelBlock; }
		
		public function get assetsLoader():AssetsLoader { return _assetsLoader; }
		
		public function get options():RenpyOptions { return _options; }
		
		public function get path():String { return _path; }
		
	}

}